package com.yj.rselasticsearch.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yj.common.config.RuoYiConfig;
import com.yj.common.constant.DataConstants;
import com.yj.common.core.domain.entity.*;
import com.yj.common.core.domain.model.LoginUser;
import com.yj.common.exception.ServiceException;
import com.yj.common.utils.FastUtils;
import com.yj.common.utils.SecurityUtils;
import com.yj.common.utils.StringUtils;
import com.yj.rselasticsearch.mapper.FileInfoMapper;
import com.yj.rselasticsearch.service.*;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 异步文件上传
 */
@Slf4j
public class FileUploadThread extends Thread {
    /**
     * 数据id
     */
    private FileInfo fileInfos;
    private FileUploadLogService fileUploadLogService;
    private FileTypeService fileTypeService;
    private TagInfoService tagInfoService;
    private FileInfoService fileInfoService;
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    private FileInfoMapper fileInfoMapper;
    private RestHighLevelClient client;
    private LoginUser loginUser;
    private FileOptionLogService fileOptionLogService;

    public FileUploadThread(FileInfo fileInfo, FileUploadLogService fileUploadLogService, FileTypeService fileTypeService, TagInfoService tagInfoService,
                            FileInfoService fileInfoService, ElasticsearchRestTemplate elasticsearchRestTemplate, FileInfoMapper fileInfoMapper, RestHighLevelClient client, LoginUser loginUser, FileOptionLogService fileOptionLogService) {
        this.fileInfos = fileInfo;
        this.fileUploadLogService = fileUploadLogService;
        this.fileTypeService = fileTypeService;
        this.tagInfoService = tagInfoService;
        this.fileInfoService = fileInfoService;
        this.elasticsearchRestTemplate = elasticsearchRestTemplate;
        this.fileInfoMapper = fileInfoMapper;
        this.client = client;
        this.loginUser = loginUser;
        this.fileOptionLogService = fileOptionLogService;
    }

    @Override
    public void run() {
        //记录上传日志
        FileUploadLog fileUploadLog = new FileUploadLog();
        fileUploadLog.setFileName(fileInfos.getFileName());
        fileUploadLog.setUploadTime(Calendar.getInstance().getTime());
        fileUploadLog.setUploadResult(DataConstants.Is.NO_INT);
        fileUploadLog.setCreateBy(loginUser.getUsername());
        fileUploadLogService.insertSelective(fileUploadLog);
        businessHand(fileUploadLog);

    }

    @Transactional(rollbackFor = Exception.class)
    public void businessHand(FileUploadLog fileUploadLog) {
        try {
            //判断一下更新了那些内容
            FileInfo fileInfo1 = new FileInfo();
            fileInfo1 = fileInfoMapper.selectOne(new LambdaQueryWrapper<FileInfo>().eq(FileInfo::getId, fileInfos.getId()));
            String optionContent = "";
            if (!fileInfo1.getFileTypeId().equals(fileInfos.getFileTypeId())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "文件类型";
                }
            }
            if (!fileInfo1.getFileUrl().equals(fileInfos.getFileUrl())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "文件附件";
                } else {
                    optionContent += ",文件附件";
                }
            }
            if (!fileInfo1.getIsOpen().equals(fileInfos.getIsOpen())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "是否公开";
                } else {
                    optionContent += ",是否公开";
                }
            }
            if (!fileInfo1.getFileName().equals(fileInfos.getFileName())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "文件名称";
                } else {
                    optionContent += ",文件名称";
                }
            }
            if (!StringUtils.isEmpty(fileInfo1.getTagId()) && StringUtils.isEmpty(fileInfos.getTagId())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "文件标签";
                } else {
                    optionContent += ",文件标签";
                }
            } else if (StringUtils.isEmpty(fileInfo1.getTagId()) && !StringUtils.isEmpty(fileInfos.getTagId())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "文件标签";
                } else {
                    optionContent += ",文件标签";
                }
            } else if (!StringUtils.isEmpty(fileInfo1.getTagId()) && !StringUtils.isEmpty(fileInfos.getTagId())) {
                if (!fileInfo1.getTagId().equals(fileInfos.getTagId())) {
                    if (StringUtils.isEmpty(optionContent)) {
                        optionContent += "文件标签";
                    } else {
                        optionContent += ",文件标签";
                    }
                }
            }

            if (!StringUtils.isEmpty(fileInfo1.getRemark()) && StringUtils.isEmpty(fileInfos.getRemark())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "备注";
                } else {
                    optionContent += ",备注";
                }
            } else if (StringUtils.isEmpty(fileInfo1.getRemark()) && !StringUtils.isEmpty(fileInfos.getRemark())) {
                if (StringUtils.isEmpty(optionContent)) {
                    optionContent += "备注";
                } else {
                    optionContent += ",备注";
                }
            } else if (!StringUtils.isEmpty(fileInfo1.getRemark()) && !StringUtils.isEmpty(fileInfos.getRemark())) {
                if (!fileInfo1.getRemark().equals(fileInfos.getRemark())) {
                    if (StringUtils.isEmpty(optionContent)) {
                        optionContent += "备注";
                    } else {
                        optionContent += ",备注";
                    }
                }
            }


            log.info(String.format("更新开始：%s", Calendar.getInstance().getTime()));
            Long starTime = Calendar.getInstance().getTime().getTime();
            // 上传文件路径
            FileInfo fileInfo = new FileInfo();
            // 上传并返回新文件名称
            String fileUrl = fileInfos.getFileUrl().substring(fileInfos.getFileUrl().indexOf("/", 1));
            String filePath = RuoYiConfig.getProfile() + fileUrl;
            FileType fileType = fileTypeService.getOne(new LambdaQueryWrapper<FileType>().eq(FileType::getFileTypeId, fileInfos.getFileTypeId().intValue()));
            File files = new File(filePath);
            fileInfo.setId(fileInfos.getId());
            fileInfo.setFileName(fileInfos.getFileName());
            fileInfo.setFileType(fileType.getFileTypeName());
            fileInfo.setFileUrl(fileInfos.getFileUrl());
            fileInfo.setFileTypeId(fileInfos.getFileTypeId());
            fileInfo.setTagId(fileInfos.getTagId());
            if (!StringUtils.isEmpty(fileInfos.getTagId())) {
                List<String> tagids = Arrays.stream(fileInfos.getTagId().split(",")).collect(Collectors.toList());
                String tagName = null;
                if (!FastUtils.checkNullOrEmpty(tagids)) {
                    for (String tagid : tagids) {
                        TagInfo tagInfo = tagInfoService.getById(tagid);
                        if (tagName == null) {
                            if (!StringUtils.isEmpty(tagInfo.getTagName())) {
                                tagName = tagInfo.getTagName() + ",";
                            }
                        } else {
                            if (!StringUtils.isEmpty(tagInfo.getTagName())) {
                                tagName += tagInfo.getTagName() + ",";
                            }
                        }
                    }
                }
                fileInfo.setTagName(tagName.substring(0, tagName.length() - 1));
            }
            fileInfo.setRemark(fileInfos.getRemark());
            fileInfo.setIsOpen(fileInfos.getIsOpen());
            fileInfo.setCreateBy(loginUser.getUsername());
            fileInfo.setDeptId(fileInfos.getDeptId());
            fileInfo.setStatus(DataConstants.Number.TWO);
            boolean result = fileInfoService.updateById(fileInfo);
            if (result) {
                //先删除文件信息
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                        .should(QueryBuilders.matchBoolPrefixQuery("id", fileInfo.getId().toString()));
                Query query = new NativeSearchQuery(boolQueryBuilder);
                elasticsearchRestTemplate.delete(query, FileInfo.class);
                //新增文件信息
                fileInfo = fileInfoMapper.selectOne(new LambdaQueryWrapper<FileInfo>().eq(FileInfo::getId, fileInfo.getId()));
                byte[] bytes = getContent(files);
                String base64 = Base64.getEncoder().encodeToString(bytes);
                fileInfo.setContent(base64);
                IndexRequest indexRequest = new IndexRequest("fileinfo");
                //上传同时，使用attachment pipline进行提取文件
                indexRequest.source(JSON.toJSONString(fileInfo), XContentType.JSON);
                indexRequest.setPipeline("attachment");
                IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
                fileInfoService.update(new LambdaUpdateWrapper<FileInfo>().eq(FileInfo::getId, fileInfo.getId()).set(FileInfo::getStatus, DataConstants.Number.ZERO));
            }
            log.info(String.format("更新结束：%s", Calendar.getInstance().getTime()));
            log.info(String.format("花费时间：%s", (starTime - Calendar.getInstance().getTime().getTime()) / 1000));
            //删除记录日志
            fileUploadLogService.deleteByPrimaryKey(fileUploadLog.getId());
            //添加操作日志
            FileOptionLog fileOptionLog = new FileOptionLog();
            fileOptionLog.setFileInfoId(fileInfo.getId());
            fileOptionLog.setOptionType(DataConstants.FILE_OPTION_TYPE.UPDATE);
            fileOptionLog.setCreateBy(loginUser.getUsername());
            fileOptionLog.setOptionContent(optionContent);
            fileOptionLogService.insertSelective(fileOptionLog);
        } catch (
                Exception e) {
            fileUploadLog.setUploadResult(DataConstants.Is.YES_INT);
            fileUploadLogService.updateByPrimaryKeySelective(fileUploadLog);
            e.printStackTrace();
            log.info(e.getMessage());
            throw new ServiceException("操作异常，请联系管理员", 500);
        }

    }

    /**
     * 文件转base64
     *
     * @param file
     * @return
     * @throws IOException
     */
    private byte[] getContent(File file) throws IOException {

        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            log.info("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new ServiceException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }
}
